/*
 *
 *  * Copyright:  2018 smarabbit studio.
 *  *
 *  *  Licensed under the Confluent Community License; you may not use this file
 *  *  except in compliance with the License.  You may obtain a copy of the License at
 *  *
 *  *  http://www.confluent.io/confluent-community-license
 *  *
 *  *  Unless required by applicable law or agreed to in writing, software
 *  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  *  specific language governing permissions and limitations under the License.
 *  *
 *  *  @作   者： 黄开晖 (117227773@qq.com)
 *  *  @日   期:    ${DATE}
 *
 */

package com.massyframework.beanskin.web.utils;

import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.assembly.AssemblyConfig;
import com.massyframework.beanskin.initparam.InitParameters;
import com.massyframework.beanskin.service.ServiceReference;
import com.massyframework.beanskin.web.servlet.DelegateServlet;



/**
 * {@link javax.servlet.ServletRegistration}工具类
 */
public abstract class ServletRegistrationUtils {

    private static final String PREFIX = "servlet";
    private static final String PREFIX_INIT = PREFIX.concat(".").concat("init-param");
    private static final String SERVLET_NAME = "name";
    private static final String SERVLET_PATH = "path";
    private static final String SERVLET_ASYNCSUPPORTED = "async-supported";
    private static final String SERVLET_LOADONSTARTUP = "load-on-startup";
    private static final String SEPARATOR = "/";


    /**
     * 从<code>initParams</code>中截取Servlet参数
     *
     * @param config {@link AssemblyConfig}, 装配件配置
     * @return {@link InitParameters}
     */
    public static InitParameters getServletParameters(AssemblyConfig config) {
        return config.subset(PREFIX);
    }

    /**
     * 根据<code>servletParams</code>创建{@link ServletRegistration}
     *
     * @param context            {@link ServletContext}, ServletContext上下文
     * @param assembly           {@link Assembly}, 装配件
     * @param defaultServletName {@link String},缺省的Servlet名称
     * @return {@link ServletRegistration}
     * @throws ServletException 
     */
    public static ServletRegistration.Dynamic createServletRegistration(
            ServletContext context,
            Assembly assembly,
            String defaultServletName,
            String defaultAsyncSupport) throws ServletException {
        InitParameters initParams = assembly.getConfig();
        return createServletRegistration(
                context,
                assembly,
                initParams.subset(PREFIX),
                initParams.subset(PREFIX_INIT),
                defaultServletName,
                defaultAsyncSupport);
    }

    /**
     * 根据<code>servletParams</code>创建{@link ServletRegistration}
     *
     * @param context          {@link ServletContext}, ServletContext上下文
     * @param assembly         {@link Assembly}, 装配件
     * @param servletSubParams {@link InitParameters}, 使用{@link #getServletParameters(AssemblyConfig)}获取的初始化子参数
     * @return {@link ServletRegistration}
     */
    public static ServletRegistration.Dynamic createServletRegistration(
            ServletContext context,
            Assembly assembly,
            InitParameters servletSubParams,
            InitParameters servletInitParams,
            String defaultServletName,
            String defaultAsyncSupport) throws ServletException {

        try {
            String servletName = servletSubParams.getParameter(SERVLET_NAME, defaultServletName);
            if (servletName == null){
                throw new ServletException(
                		String.format("cannot found initparams: name= \"servlet.%s\" , please set it.", SERVLET_NAME));
            }
            ServletRegistration.Dynamic result = context.addServlet(servletName, new DelegateServlet());
            if (result == null){
                throw new ServletException(
                		String.format("servle is exists: servletName = \"%s\".", servletName));
            }

            //path： url-pattern的变体，
            String path = servletSubParams.getParameter(SERVLET_PATH);
            if (path == null) {
                throw new ServletException("cannot found Servlet parameter: \"path\" .");
            }
            if (!path.startsWith(SEPARATOR)) {
                path = SEPARATOR.concat(path);
            }
            if (path.endsWith("/")) {
                path = path.substring(0, path.length() - 1);
            } else {
                if (path.endsWith("/*")) {
                    path = path.substring(0, path.length() - 2);
                }
            }

            String urlPattern = path.concat(SEPARATOR).concat("*");
            result.addMapping(urlPattern);

            //异步支持
            String asyncSupported = servletSubParams.getParameter(SERVLET_ASYNCSUPPORTED, "true");
            boolean supported = Boolean.parseBoolean(asyncSupported);
            result.setAsyncSupported(supported);

            //启动次序
            String loadOnStartup = servletSubParams.getParameter(SERVLET_LOADONSTARTUP);
            if (loadOnStartup != null) {
                result.setLoadOnStartup(Integer.parseInt(loadOnStartup));
            }

            //设置属性
            List<String> names = servletInitParams.getParameterNames();
            for (String name : names) {
                String value = servletInitParams.getParameter(name);
                result.setInitParameter(name, value);
            }
            result.setInitParameter(ServiceReference.MODULE_GROUPID, assembly.getGroupId());
            result.setInitParameter(ServiceReference.MODULE_MODULEID, assembly.getModuleId());
            result.setInitParameter(ServiceReference.MODULE_VERSION, assembly.getVersion().toString());
            return result;
        } catch (ServletException e) {
        	throw e;
        } catch (Exception e) {
            throw new ServletException("create Servlet failed.", e);
        }
    }

}
